﻿namespace MicroCloud.Entity
{
    /// <summary>
    /// 实体数据存储操作类
    /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <typeparam name="TKey">实体主键类型</typeparam>
    public class Repository<TEntity, TKey> : IRepository<TEntity, TKey>
        where TEntity : class, IEntity<TKey>, new()
        where TKey : IEquatable<TKey>
    {
        #region "构造函数"
        #region "初始化一个实体数据存储操作类的新实例"
        /// <summary>
        /// 初始化一个实体数据存储操作类 <see cref="Repository{TEntity, TKey}"/> 的新实例
        /// </summary>
        /// <param name="serviceProvider">服务提供者</param>
        public Repository(IServiceProvider serviceProvider)
        {
            ServiceProvider = serviceProvider;
        }
        #endregion

        #endregion

        #region "属性"
        //受保护属性
        #region "获取 服务提供者"
        /// <summary>
        /// 获取 服务提供者
        /// </summary>
        protected IServiceProvider ServiceProvider { get; }
        #endregion
        #region "获取 日志记录器"
        /// <summary>
        /// 获取 日志记录器
        /// </summary>
        protected ILogger Logger => ServiceProvider.GetLogger<Repository<TEntity, TKey>>();
        #endregion
        #region "获取 异步任务取消标识提供器"
        /// <summary>
        /// 获取 异步任务取消标识提供器
        /// </summary>
        protected ICancellationTokenProvider CancellationTokenProvider => ServiceProvider.GetRequiredService<ICancellationTokenProvider>();
        #endregion
        #region "获取 当前用户的基本功能"
        /// <summary>
        /// 获取 当前用户的基本功能
        /// </summary>
        protected IPrincipal Principal => ServiceProvider.GetService<IPrincipal>();
        #endregion
        #region "获取 系统配置选项信息"
        /// <summary>
        /// 获取 系统配置选项信息
        /// </summary>
        protected MicroCloudOptions Options => ServiceProvider.GetService<IOptions<MicroCloudOptions>>()?.Value;
        #endregion
        #region "获取 数据权限服务"
        /// <summary>
        /// 获取 数据权限服务
        /// </summary>
        protected IDataAuthService DataAuthService => ServiceProvider.GetService<IDataAuthService>();
        #endregion
        #region "获取 序列化值的分布式缓存对象"
        /// <summary>
        /// 获取 序列化值的分布式缓存对象
        /// </summary>
        protected IDistributedCache DistributedCache => ServiceProvider.GetRequiredService<IDistributedCache>();
        #endregion

        #region "获取 基于Scoped生命周期的数据字典"
        /// <summary>
        /// 获取 基于Scoped生命周期的数据字典
        /// </summary>
        protected ScopedDictionary ScopedDict => ServiceProvider.GetService<ScopedDictionary>();
        #endregion

        #region "获取 实体数据设置对象"
        /// <summary>
        /// 获取 实体数据设置对象
        /// </summary>
        protected DbSet<TEntity> DbSet => ((DbContext)DbContext).Set<TEntity>();
        #endregion

        //公共属性
        #region "获取 数据上下文"
        /// <summary>
        /// 获取 数据上下文
        /// </summary>
        public IDbContext DbContext => ServiceProvider.GetDbContext<TEntity, TKey>();
        #endregion

        #endregion

        #region "同步方法"
        #region "插入实体"
        /// <summary>
        /// 插入实体
        /// </summary>
        /// <param name="entities">实体对象集合</param>
        /// <returns>操作结果</returns>
        public virtual OperationResult Insert(params TEntity[] entities)
        {
            Check.NotNull(entities, nameof(entities));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            entities = CheckInsert<TEntity, TKey>(entities);
            DbSet.AddRange(entities);
            object count = DbContext.SaveChanges();

            unitOfWork.Commit();

            return OperationResult.Success(count, I18N.T("{0}个记录添加成功", count));
        }
        #endregion
        #region "插入或更新实体"
        /// <summary>
        /// 插入或更新实体
        /// </summary>
        /// <param name="entities">要处理的实体</param>
        /// <param name="existingFunc">实体是否存在的判断委托</param>
        /// <returns>操作结果</returns>
        public virtual OperationResult InsertOrUpdate(TEntity[] entities, Func<TEntity, Expression<Func<TEntity, bool>>> existingFunc = null)
        {
            Check.NotNull(entities, nameof(entities));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            foreach (TEntity entity in entities)
            {
                Expression<Func<TEntity, bool>> exp = existingFunc == null
                    ? m => m.Id.Equals(entity.Id)
                    : existingFunc(entity);
                if (!DbSet.Any(exp))
                {
                    CheckInsert<TEntity, TKey>(entity);
                    DbSet.Add(entity);
                }
                else
                {
                    CheckUpdate<TEntity, TKey>(entity);
                    ((DbContext)DbContext).Update<TEntity, TKey>(entity);
                }
            }
            object count = DbContext.SaveChanges();

            unitOfWork.Commit();

            return OperationResult.Success(count, I18N.T("{0}个记录添加或更新成功", count));
        }
        #endregion
        #region "以DTO为载体批量插入实体"
        /// <summary>
        /// 以DTO为载体批量插入实体
        /// </summary>
        /// <typeparam name="TInputDto">添加DTO类型</typeparam>
        /// <param name="dtos">添加DTO信息集合</param>
        /// <param name="checkAction">添加信息合法性检查委托</param>
        /// <param name="updateFunc">由DTO到实体的转换委托</param>
        /// <returns>业务操作结果</returns>
        public virtual OperationResult Insert<TInputDto>(ICollection<TInputDto> dtos, Action<TInputDto> checkAction = null, Func<TInputDto, TEntity, TEntity> updateFunc = null)
            where TInputDto : class, IInputDto<TKey>
        {
            Check.NotNull(dtos, nameof(dtos));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            Dictionary<TInputDto, TEntity> dict = new();
            foreach (TInputDto dto in dtos)
            {
                try
                {
                    checkAction?.Invoke(dto);

                    TEntity entity = dto.MapTo<TInputDto, TEntity>();
                    entity = CheckInsert<TEntity, TKey>(entity)[0];

                    if (updateFunc != null)
                    {
                        entity = updateFunc(dto, entity);
                    }

                    DbSet.Add(entity);
                    dict.Add(dto, entity);
                }
                catch (Exception e)
                {
                    Logger.LogError(e, "{msg}", e.Message);
                    return OperationResult.Error(e.Message);
                }
            }
            object count = DbContext.SaveChanges();
            foreach (var item in dict)
            {
                item.Key.Id = item.Value.Id;
            }

            unitOfWork.Commit();

            return OperationResult.Success(count, I18N.T("{0}个记录添加成功", count));
        }
        #endregion
        #region "删除实体"
        /// <summary>
        /// 删除实体
        /// </summary>
        /// <param name="entities">实体对象集合</param>
        /// <returns>操作结果</returns>
        public virtual OperationResult Delete(params TEntity[] entities)
        {
            Check.NotNull(entities, nameof(entities));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            DeleteInternal<TEntity, TKey>(entities);
            object count = DbContext.SaveChanges();

            unitOfWork.Commit();

            return OperationResult.Success(count, I18N.T("{0}个记录删除成功", count));
        }
        #endregion
        #region "删除指定编号的实体"
        /// <summary>
        /// 删除指定编号的实体
        /// </summary>
        /// <param name="key">实体主键</param>
        /// <returns>操作结果</returns>
        public virtual OperationResult Delete(TKey key)
        {
            CheckEntityKey(key, nameof(key));

            TEntity entity = DbSet.Find(key);
            if (entity == null)
            {
                object count = 0;
                return OperationResult.Success(count, I18N.T("{0}个记录删除成功", count));
            }
            return Delete(entity);
        }
        #endregion
        #region "以标识集合批量删除实体"
        /// <summary>
        /// 以标识集合批量删除实体
        /// </summary>
        /// <param name="ids">标识集合</param>
        /// <param name="checkAction">删除前置检查委托</param>
        /// <param name="deleteFunc">删除委托，用于删除关联信息</param>
        /// <returns>业务操作结果</returns>
        public virtual OperationResult Delete(ICollection<TKey> ids, Action<TEntity> checkAction = null, Func<TEntity, TEntity> deleteFunc = null)
        {
            Check.NotNull(ids, nameof(ids));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            foreach (TKey id in ids)
            {
                TEntity entity = DbSet.Find(id);
                if (entity == null)
                {
                    continue;
                }
                try
                {
                    checkAction?.Invoke(entity);
                    if (deleteFunc != null)
                    {
                        entity = deleteFunc(entity);
                    }
                    DeleteInternal<TEntity, TKey>(entity);
                }
                catch (Exception e)
                {
                    Logger.LogError(e, "{msg}", e.Message);
                    return OperationResult.Error(e.Message);
                }
            }
            object count = DbContext.SaveChanges();

            unitOfWork.Commit();

            return OperationResult.Success(count, I18N.T("{0}个记录删除成功", count));
        }
        #endregion
        #region "删除所有符合特定条件的实体"
        /// <summary>
        /// 删除所有符合特定条件的实体
        /// </summary>
        /// <param name="predicate">查询条件谓语表达式</param>
        /// <returns>业务操作结果</returns>
        public virtual OperationResult DeleteBatch(Expression<Func<TEntity, bool>> predicate)
        {
            Check.NotNull(predicate, nameof(predicate));

            #region "注释备查"
            //IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);
            ////走EF.Plus的时候，是不调用SaveChanges的，需要手动开启事务
            //((DbContextBase)DbContext).BeginOrUseTransaction();

            //object count = 0;
            //if (typeof(ISoftDeletable).IsAssignableFrom(typeof(TEntity)))
            //{
            //    // 逻辑删除
            //    TEntity[] entities = DbSet.Where(predicate).ToArray();
            //    DeleteInternal<TEntity, TKey>(entities);
            //    count = DbContext.SaveChanges();
            //}
            //else
            //{
            //    //物理删除
            //    count = DbSet.Where(predicate).Delete();
            //}

            //unitOfWork.Commit();

            //return OperationResult.Success(count, I18N.T("{0}个记录删除成功", count));
            #endregion

            TEntity[] entities = DbSet.Where(predicate).ToArray();
            return Delete(entities);
        }
        #endregion
        #region "更新实体对象"
        /// <summary>
        /// 更新实体对象
        /// </summary>
        /// <param name="entities">更新后的实体对象</param>
        /// <returns>操作结果</returns>
        public virtual OperationResult Update(params TEntity[] entities)
        {
            Check.NotNull(entities, nameof(entities));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            entities = CheckUpdate<TEntity, TKey>(entities);
            ((DbContext)DbContext).Update<TEntity, TKey>(entities);
            object count = DbContext.SaveChanges();

            unitOfWork.Commit();

            return OperationResult.Success(count, I18N.T("{0}个记录更新成功", count));
        }
        #endregion
        #region "以DTO为载体批量更新实体"
        /// <summary>
        /// 以DTO为载体批量更新实体
        /// </summary>
        /// <typeparam name="TEditDto">更新DTO类型</typeparam>
        /// <param name="dtos">更新DTO信息集合</param>
        /// <param name="checkAction">更新信息合法性检查委托</param>
        /// <param name="updateFunc">由DTO到实体的转换委托</param>
        /// <returns>业务操作结果</returns>
        public virtual OperationResult Update<TEditDto>(ICollection<TEditDto> dtos, Action<TEditDto, TEntity> checkAction = null, Func<TEditDto, TEntity, TEntity> updateFunc = null)
            where TEditDto : IInputDto<TKey>
        {
            Check.NotNull(dtos, nameof(dtos));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            foreach (TEditDto dto in dtos)
            {
                try
                {
                    TEntity entity = DbSet.Find(dto.Id);
                    if (entity == null)
                    {
                        return OperationResult.NotFound(I18N.T("编号为 {0} 的 {1} 不存在", dto.Id, typeof(TEntity).GetDescription()));
                    }
                    checkAction?.Invoke(dto, entity);

                    entity = dto.MapTo(entity);
                    entity = CheckUpdate<TEntity, TKey>(entity)[0];

                    if (updateFunc != null)
                    {
                        entity = updateFunc(dto, entity);
                    }

                    ((DbContext)DbContext).Update<TEntity, TKey>(entity);
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex, "{msg}", ex.Message);
                    return OperationResult.Error(ex.Message);
                }
            }
            object count = DbContext.SaveChanges();

            unitOfWork.Commit();

            return OperationResult.Success(count, I18N.T("{0}个记录更新成功", count));
        }
        #endregion
        #region "批量更新所有符合特定条件的实体"
        /// <summary>
        /// 批量更新所有符合特定条件的实体
        /// </summary>
        /// <param name="predicate">查询条件的谓语表达式</param>
        /// <param name="updateExpression">属性更新表达式</param>
        /// <returns>业务操作结果</returns>
        public virtual OperationResult UpdateBatch(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, TEntity>> updateExpression)
        {
            Check.NotNull(predicate, nameof(predicate));
            Check.NotNull(updateExpression, nameof(updateExpression));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);
            //走EF.Plus的时候，是不调用SaveChanges的，需要手动开启事务
            ScopedDictionary dict = ServiceProvider.GetService<ScopedDictionary>();
            ((DbContextBase)DbContext).BeginOrUseTransaction(dict?.IsolationLevel);

            object count = DbSet.Where(predicate).Update(updateExpression);

            unitOfWork.Commit();

            return OperationResult.Success(count, I18N.T("{0}个记录更新成功", count));
        }
        #endregion
        #region "检查实体是否存在"
        /// <summary>
        /// 检查实体是否存在
        /// </summary>
        /// <param name="predicate">查询条件谓语表达式</param>
        /// <param name="id">编辑的实体标识</param>
        /// <returns>是否存在</returns>
        public virtual bool CheckExists(Expression<Func<TEntity, bool>> predicate, TKey id = default)
        {
            Check.NotNull(predicate, nameof(predicate));

            TKey defaultId = default;
            var entity = DbSet.Where(predicate).Select(m => new { m.Id }).FirstOrDefault();
            bool exists = !typeof(TKey).IsValueType && id is null || id.Equals(defaultId)
                ? entity != null
                : entity != null && !EntityBase<TKey>.IsKeyEqual(entity.Id, id);
            return exists;
        }
        #endregion
        #region "查找指定主键的实体"
        /// <summary>
        /// 查找指定主键的实体
        /// </summary>
        /// <param name="key">实体主键</param>
        /// <returns>符合主键的实体，不存在时返回null</returns>
        public virtual TEntity Get(TKey key)
        {
            CheckEntityKey(key, nameof(key));

            return DbSet.Find(key);
        }
        #endregion
        
        #region "查找第一个符合条件的数据"
        /// <summary>
        /// 查找第一个符合条件的数据
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <returns>符合条件的实体，不存在时返回null</returns>
        public virtual TEntity GetFirst(Expression<Func<TEntity, bool>> predicate)
        {
            predicate.CheckNotNull(nameof(predicate));

            return GetFirst(predicate, true);
        }
        #endregion
        #region "查找第一个符合条件的数据"
        /// <summary>
        /// 查找第一个符合条件的数据
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <param name="filterByDataAuth">是否使用数据权限过滤，数据权限一般用于存在用户实例的查询，系统查询不启用数据权限过滤</param>
        /// <returns>符合条件的实体，不存在时返回null</returns>
        public virtual TEntity GetFirst(Expression<Func<TEntity, bool>> predicate, bool filterByDataAuth)
        {
            Check.NotNull(predicate, nameof(predicate));
            return Query(predicate, filterByDataAuth).FirstOrDefault();
        }
        #endregion
        #region "查找符合条件的数据列表"
        /// <summary>
        /// 查找符合条件的数据列表
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <returns>符合条件的实体列表</returns>
        public virtual List<TEntity> GetList(Expression<Func<TEntity, bool>> predicate)
        {
            predicate.CheckNotNull(nameof(predicate));

            return GetList(predicate, true);
        }
        #endregion
        #region "查找符合条件的数据列表"
        /// <summary>
        /// 查找符合条件的数据列表
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <param name="filterByDataAuth">是否使用数据权限过滤，数据权限一般用于存在用户实例的查询，系统查询不启用数据权限过滤</param>
        /// <returns>符合条件的实体列表</returns>
        public virtual List<TEntity> GetList(Expression<Func<TEntity, bool>> predicate, bool filterByDataAuth)
        {
            Check.NotNull(predicate, nameof(predicate));
            return Query(predicate, filterByDataAuth).ToList();
        }
        #endregion
        #region "查找符合条件的数据数组"
        /// <summary>
        /// 查找符合条件的数据数组
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <returns>符合条件的实体数组</returns>
        public virtual TEntity[] GetArray(Expression<Func<TEntity, bool>> predicate)
        {
            predicate.CheckNotNull(nameof(predicate));

            return GetArray(predicate, true);
        }
        #endregion
        #region "查找符合条件的数据数组"
        /// <summary>
        /// 查找符合条件的数据数组
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <param name="filterByDataAuth">是否使用数据权限过滤，数据权限一般用于存在用户实例的查询，系统查询不启用数据权限过滤。</param>
        /// <returns>符合条件的实体数组</returns>
        public virtual TEntity[] GetArray(Expression<Func<TEntity, bool>> predicate, bool filterByDataAuth)
        {
            Check.NotNull(predicate, nameof(predicate));
            return Query(predicate, filterByDataAuth).ToArray();
        }
        #endregion

        #region "获取 <typeparamref name="TEntity"/> 不跟踪数据更改 NoTracking 的查询数据源"
        /// <summary>
        /// 获取 <typeparamref name="TEntity"/> 不跟踪数据更改 NoTracking 的查询数据源
        /// </summary>
        /// <returns>符合条件的数据集</returns>
        public virtual IQueryable<TEntity> QueryAsNoTracking()
        {
            return QueryAsNoTracking(null, true);
        }
        #endregion
        #region "获取 <typeparamref name="TEntity"/> 不跟踪数据更改 NoTracking 的查询数据源"
        /// <summary>
        /// 获取 <typeparamref name="TEntity"/> 不跟踪数据更改 NoTracking 的查询数据源
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <returns>符合条件的数据集</returns>
        public virtual IQueryable<TEntity> QueryAsNoTracking(Expression<Func<TEntity, bool>> predicate)
        {
            return QueryAsNoTracking(predicate, true);
        }
        #endregion
        #region "获取 <typeparamref name="TEntity"/> 不跟踪数据更改 NoTracking 的查询数据源，并可附加过滤条件及是否启用数据权限过滤。"
        /// <summary>
        /// 获取 <typeparamref name="TEntity"/> 不跟踪数据更改 NoTracking 的查询数据源，并可附加过滤条件及是否启用数据权限过滤。
        /// </summary>
        /// <param name="predicate">数据过滤表达式</param>
        /// <param name="filterByDataAuth">是否使用数据权限过滤，数据权限一般用于存在用户实例的查询，系统查询不启用数据权限过滤。</param>
        /// <returns>符合条件的数据集</returns>
        public virtual IQueryable<TEntity> QueryAsNoTracking(Expression<Func<TEntity, bool>> predicate, bool filterByDataAuth)
        {
            return Query(predicate, filterByDataAuth).AsNoTracking();
        }
        #endregion
        #region "获取 <typeparamref name="TEntity"/> 不跟踪数据更改 NoTracking 的查询数据源，并可Include导航属性。"
        /// <summary>
        /// 获取 <typeparamref name="TEntity"/> 不跟踪数据更改 NoTracking 的查询数据源，并可Include导航属性。
        /// </summary>
        /// <param name="includePropertySelectors">要Include操作的属性表达式</param>
        /// <returns>符合条件的数据集</returns>
        public virtual IQueryable<TEntity> QueryAsNoTracking(params Expression<Func<TEntity, object>>[] includePropertySelectors)
        {
            return Query(includePropertySelectors).AsNoTracking();
        }
        #endregion
        #region "获取 <typeparamref name="TEntity"/> 跟踪数据更改 Tracking 的查询数据源"
        /// <summary>
        /// 获取 <typeparamref name="TEntity"/> 跟踪数据更改 Tracking 的查询数据源
        /// </summary>
        /// <returns>符合条件的数据集</returns>
        public virtual IQueryable<TEntity> Query()
        {
            return Query(null, true);
        }
        #endregion
        #region "获取 <typeparamref name="TEntity"/> 跟踪数据更改 Tracking 的查询数据源"
        /// <summary>
        /// 获取 <typeparamref name="TEntity"/> 跟踪数据更改 Tracking 的查询数据源
        /// </summary>
        /// <param name="predicate">数据过滤表达式</param>
        /// <returns>符合条件的数据集</returns>
        public virtual IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> predicate)
        {
            return Query(predicate, true);
        }
        #endregion
        #region "获取 <typeparamref name="TEntity"/> 跟踪数据更改 Tracking 的查询数据源，并可附加过滤条件及是否启用数据权限过滤。"
        /// <summary>
        /// 获取 <typeparamref name="TEntity"/> 跟踪数据更改 Tracking 的查询数据源，并可附加过滤条件及是否启用数据权限过滤。
        /// </summary>
        /// <param name="predicate">数据过滤表达式</param>
        /// <param name="filterByDataAuth">是否使用数据权限过滤，数据权限一般用于存在用户实例的查询，系统查询不启用数据权限过滤</param>
        /// <returns>符合条件的数据集</returns>
        public IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> predicate, bool filterByDataAuth)
        {
            IQueryable<TEntity> query = DbSet.AsQueryable();
            if (filterByDataAuth && DataAuthService != null)
            {
                Expression<Func<TEntity, bool>> dataAuthExp = DataAuthService.GetDataFilter<TEntity>(DataAuthOperation.Read);
                query = query.Where(dataAuthExp);
            }
            if (predicate == null)
            {
                return query;
            }
            return query.Where(predicate);
        }
        #endregion
        #region "获取 <typeparamref name="TEntity"/> 跟踪数据更改 Tracking 的查询数据源，并可Include导航属性。"
        /// <summary>
        /// 获取 <typeparamref name="TEntity"/> 跟踪数据更改 Tracking 的查询数据源，并可Include导航属性。
        /// </summary>
        /// <param name="includePropertySelectors">要Include操作的属性表达式</param>
        /// <returns>符合条件的数据集</returns>
        public virtual IQueryable<TEntity> Query(params Expression<Func<TEntity, object>>[] includePropertySelectors)
        {
            IQueryable<TEntity> query = DbSet.AsQueryable();
            if (includePropertySelectors == null || includePropertySelectors.Length == 0)
            {
                return query;
            }

            foreach (Expression<Func<TEntity, object>> selector in includePropertySelectors)
            {
                query = query.Include(selector);
            }
            return query.AsSplitQuery();
        }
        #endregion

        #region "将第一个符合条件的数据转换为缓存的结果，如缓存存在，直接返回，否则从数据源查询，并存入缓存中再返回"
        /// <summary>
        /// 将第一个符合条件的数据转换为缓存的结果，如缓存存在，直接返回，否则从数据源查询，并存入缓存中再返回
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <param name="cacheSeconds">缓存的秒数</param>
        /// <param name="absolute">是否绝对过期</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns>符合条件的实体，不存在时返回默认值。</returns>
        public TEntity ToCacheFirst(Expression<Func<TEntity, bool>> predicate, int cacheSeconds = 60, bool absolute = true, TEntity defaultValue = null)
        {
            predicate.CheckNotNull(nameof(predicate));

            return ToCacheFirst(predicate, true, cacheSeconds, absolute, defaultValue);
        }
        #endregion
        #region "将第一个符合条件的数据转换为缓存的结果，如缓存存在，直接返回，否则从数据源查询，并存入缓存中再返回"
        /// <summary>
        /// 将第一个符合条件的数据转换为缓存的结果，如缓存存在，直接返回，否则从数据源查询，并存入缓存中再返回
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <param name="filterByDataAuth">是否使用数据权限过滤，数据权限一般用于存在用户实例的查询，系统查询不启用数据权限过滤</param>
        /// <param name="cacheSeconds">缓存的秒数</param>
        /// <param name="absolute">是否绝对过期</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns>符合条件的实体，不存在时返回默认值。</returns>
        public TEntity ToCacheFirst(Expression<Func<TEntity, bool>> predicate, bool filterByDataAuth, int cacheSeconds = 60, bool absolute = true, TEntity defaultValue = null)
        {
            predicate.CheckNotNull(nameof(predicate));

            string key = new ExpressionCacheKeyGenerator(predicate).GetKey();
            key = $"Repository:ToCacheFirst:{key.ToMD5()}";
            var entity = DistributedCache.Get(key, () => GetFirst(predicate, filterByDataAuth), cacheSeconds, absolute);
            return entity ?? defaultValue;
        }
        #endregion

        #region "将符合条件的数据列表转换为缓存的结果，如缓存存在，直接返回，否则从数据源查询，并存入缓存中再返回。"
        /// <summary>
        /// 将符合条件的数据列表转换为缓存的结果，如缓存存在，直接返回，否则从数据源查询，并存入缓存中再返回。
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <param name="cacheSeconds">缓存的秒数</param>
        /// <param name="absolute">是否绝对过期</param>
        /// <returns>符合条件的实体列表</returns>
        public virtual List<TEntity> ToCacheList(Expression<Func<TEntity, bool>> predicate, int cacheSeconds = 60, bool absolute = true)
        {
            predicate.CheckNotNull(nameof(predicate));

            return ToCacheList(predicate, true, cacheSeconds, absolute);
        }
        #endregion
        #region "将符合条件的数据列表转换为缓存的结果，如缓存存在，直接返回，否则从数据源查询，并存入缓存中再返回。"
        /// <summary>
        /// 将符合条件的数据列表转换为缓存的结果，如缓存存在，直接返回，否则从数据源查询，并存入缓存中再返回。
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <param name="filterByDataAuth">是否使用数据权限过滤，数据权限一般用于存在用户实例的查询，系统查询不启用数据权限过滤。</param>
        /// <param name="cacheSeconds">缓存的秒数</param>
        /// <param name="absolute">是否绝对过期</param>
        /// <returns>符合条件的实体列表</returns>
        public virtual List<TEntity> ToCacheList(Expression<Func<TEntity, bool>> predicate, bool filterByDataAuth, int cacheSeconds = 60, bool absolute = true)
        {
            predicate.CheckNotNull(nameof(predicate));

            string key = new ExpressionCacheKeyGenerator(predicate).GetKey();
            key = $"Repository:ToCacheList:{key.ToMD5()}";
            var entities = DistributedCache.Get(key, () => GetList(predicate, filterByDataAuth), cacheSeconds, absolute);
            return entities;
        }
        #endregion
        #region "将符合条件的数据数组转换为缓存的结果，如缓存存在，直接返回，否则从数据源查询，并存入缓存中再返回。"
        /// <summary>
        /// 将符合条件的数据数组转换为缓存的结果，如缓存存在，直接返回，否则从数据源查询，并存入缓存中再返回。
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <param name="cacheSeconds">缓存的秒数</param>
        /// <param name="absolute">是否绝对过期</param>
        /// <returns>符合条件的实体数组</returns>
        public virtual TEntity[] ToCacheArray(Expression<Func<TEntity, bool>> predicate, int cacheSeconds = 60, bool absolute = true)
        {
            predicate.CheckNotNull(nameof(predicate));

            return ToCacheArray(predicate, true, cacheSeconds, absolute);
        }
        #endregion
        #region "将符合条件的数据数组转换为缓存的结果，如缓存存在，直接返回，否则从数据源查询，并存入缓存中再返回。"
        /// <summary>
        /// 将符合条件的数据数组转换为缓存的结果，如缓存存在，直接返回，否则从数据源查询，并存入缓存中再返回。
        /// </summary>
        /// <param name="predicate">数据查询谓语表达式</param>
        /// <param name="filterByDataAuth">是否使用数据权限过滤，数据权限一般用于存在用户实例的查询，系统查询不启用数据权限过滤。</param>
        /// <param name="cacheSeconds">缓存的秒数</param>
        /// <param name="absolute">是否绝对过期</param>
        /// <returns>符合条件的实体数组</returns>
        public virtual TEntity[] ToCacheArray(Expression<Func<TEntity, bool>> predicate, bool filterByDataAuth, int cacheSeconds = 60, bool absolute = true)
        {
            predicate.CheckNotNull(nameof(predicate));

            string key = new ExpressionCacheKeyGenerator(predicate).GetKey();
            key = $"Repository:ToCacheArray:{key.ToMD5()}";
            var entities = DistributedCache.Get(key, () => GetArray(predicate, filterByDataAuth), cacheSeconds, absolute);
            return entities;
        }
        #endregion

        #region "SQL LIKE操作的实现。在关系数据库中，这是通常直接翻译成SQL。"
        /// <summary>
        /// SQL LIKE操作的实现。在关系数据库中，这是通常直接翻译成SQL。
        /// </summary>
        /// <param name="matchExpression">要匹配的字符串。</param>
        /// <param name="pattern">可能涉及通配符%、_、[、]、^的模式。</param>
        /// <param name="escapeCharacter">如果%、_、[、]、^未用作通配符，则在它们前面使用的转义符（作为单个字符串）。</param>
        /// <returns>如果匹配，则为true</returns>
        public bool Like(string matchExpression, string pattern, string escapeCharacter = @"\")
        {
            return EF.Functions.Like(matchExpression, pattern, escapeCharacter);
        }
        #endregion

        #endregion

        #region "异步方法"
        #region "异步插入实体"
        /// <summary>
        /// 异步插入实体
        /// </summary>
        /// <param name="entities">实体对象集合</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> InsertAsync(params TEntity[] entities)
        {
            Check.NotNull(entities, nameof(entities));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            entities = CheckInsert<TEntity, TKey>(entities);
            await DbSet.AddRangeAsync(entities, CancellationTokenProvider.Token);
            object count = null;
            count = await DbContext.SaveChangesAsync(CancellationTokenProvider.Token);
            await unitOfWork.CommitAsync(CancellationTokenProvider.Token);

            return OperationResult.Success(count, I18N.T("{0}个记录添加成功", count));
        }
        #endregion
        #region "插入或更新实体"
        /// <summary>
        /// 插入或更新实体
        /// </summary>
        /// <param name="entities">要处理的实体</param>
        /// <param name="existingFunc">实体是否存在的判断委托</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> InsertOrUpdateAsync(TEntity[] entities, Func<TEntity, Expression<Func<TEntity, bool>>> existingFunc = null)
        {
            Check.NotNull(entities, nameof(entities));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            foreach (TEntity entity in entities)
            {
                Expression<Func<TEntity, bool>> exp = existingFunc == null ? m => m.Id.Equals(entity.Id) : existingFunc(entity);
                if (!await DbSet.AnyAsync(exp))
                {
                    CheckInsert<TEntity, TKey>(entity);
                    await DbSet.AddAsync(entity);
                }
                else
                {
                    CheckUpdate<TEntity, TKey>(entity);
                    ((DbContext)DbContext).Update<TEntity, TKey>(entity);
                }
            }
            object count = await DbContext.SaveChangesAsync(CancellationTokenProvider.Token);

            await unitOfWork.CommitAsync(CancellationTokenProvider.Token);

            return OperationResult.Success(count, I18N.T("{0}个记录添加或更新成功", count));
        }
        #endregion
        #region "异步以DTO为载体批量插入实体"
        /// <summary>
        /// 异步以DTO为载体批量插入实体
        /// </summary>
        /// <typeparam name="TInputDto">添加DTO类型</typeparam>
        /// <param name="dtos">添加DTO信息集合</param>
        /// <param name="checkAction">添加信息合法性检查委托</param>
        /// <param name="updateFunc">由DTO到实体的转换委托</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> InsertAsync<TInputDto>(ICollection<TInputDto> dtos, Func<TInputDto, Task> checkAction = null, Func<TInputDto, TEntity, Task<TEntity>> updateFunc = null)
            where TInputDto : class, IInputDto<TKey>
        {
            Check.NotNull(dtos, nameof(dtos));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            Dictionary<TInputDto, TEntity> dict = new();
            foreach (TInputDto dto in dtos)
            {
                try
                {
                    if (checkAction != null)
                    {
                        await checkAction(dto);
                    }

                    TEntity entity = dto.MapTo<TInputDto, TEntity>();
                    entity = CheckInsert<TEntity, TKey>(entity)[0];

                    if (updateFunc != null)
                    {
                        entity = await updateFunc(dto, entity);
                    }

                    await DbSet.AddAsync(entity, CancellationTokenProvider.Token);
                    dict.Add(dto, entity);
                }
                catch (Exception e)
                {
                    Logger.LogError(e, "{msg}", e.Message);
                    return OperationResult.Error(e.Message);
                }
            }
            object count = await DbContext.SaveChangesAsync(CancellationTokenProvider.Token);
            foreach (var item in dict)
            {
                item.Key.Id = item.Value.Id;
            }

            await unitOfWork.CommitAsync(CancellationTokenProvider.Token);

            return OperationResult.Success(count, I18N.T("{0}个记录添加成功", count));
        }
        #endregion
        #region "异步删除实体"
        /// <summary>
        /// 异步删除实体
        /// </summary>
        /// <param name="entities">实体对象集合</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> DeleteAsync(params TEntity[] entities)
        {
            Check.NotNull(entities, nameof(entities));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            DeleteInternal<TEntity, TKey>(entities);
            object count = await DbContext.SaveChangesAsync(CancellationTokenProvider.Token);

            await unitOfWork.CommitAsync(CancellationTokenProvider.Token);

            return OperationResult.Success(count, I18N.T("{0}个记录删除成功", count));
        }
        #endregion
        #region "异步删除指定编号的实体"
        /// <summary>
        /// 异步删除指定编号的实体
        /// </summary>
        /// <param name="key">实体编号</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> DeleteAsync(TKey key)
        {
            CheckEntityKey(key, nameof(key));

            TEntity entity = await DbSet.FindAsync(key);
            if (entity == null)
            {
                object count = 0;
                return OperationResult.Success(count, I18N.T("{0}个记录删除成功", count));
            }
            return await DeleteAsync(entity);
        }
        #endregion
        #region "异步以标识集合批量删除实体"
        /// <summary>
        /// 异步以标识集合批量删除实体
        /// </summary>
        /// <param name="ids">标识集合</param>
        /// <param name="checkAction">删除前置检查委托</param>
        /// <param name="deleteFunc">删除委托，用于删除关联信息</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> DeleteAsync(ICollection<TKey> ids, Func<TEntity, Task> checkAction = null, Func<TEntity, Task<TEntity>> deleteFunc = null)
        {
            Check.NotNull(ids, nameof(ids));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            foreach (TKey id in ids)
            {
                TEntity entity = DbSet.Find(id);
                if (entity == null)
                {
                    continue;
                }
                try
                {
                    if (checkAction != null)
                    {
                        await checkAction(entity);
                    }
                    if (deleteFunc != null)
                    {
                        entity = await deleteFunc(entity);
                    }
                    DeleteInternal<TEntity, TKey>(entity);
                }
                catch (Exception e)
                {
                    Logger.LogError(e, "{msg}", e.Message);
                    return OperationResult.Error(e.Message);
                }
            }
            object count = await DbContext.SaveChangesAsync(CancellationTokenProvider.Token);

            await unitOfWork.CommitAsync(CancellationTokenProvider.Token);

            return OperationResult.Success(count, I18N.T("{0}个记录删除成功", count));
        }
        #endregion
        #region "异步删除所有符合特定条件的实体"
        /// <summary>
        /// 异步删除所有符合特定条件的实体
        /// </summary>
        /// <param name="predicate">查询条件谓语表达式</param>
        /// <returns>操作影响的行数</returns>
        public virtual async Task<OperationResult> DeleteBatchAsync(Expression<Func<TEntity, bool>> predicate)
        {
            Check.NotNull(predicate, nameof(predicate));

            #region "注释备查"
            //IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);
            ////走EF.Plus的时候，是不调用SaveChanges的，需要手动开启事务
            //await ((DbContextBase)DbContext).BeginOrUseTransactionAsync(CancellationTokenProvider.Token);

            //object count = 0;
            //if (typeof(ISoftDeletable).IsAssignableFrom(typeof(TEntity)))
            //{
            //    // 逻辑删除
            //    TEntity[] entities = DbSet.Where(predicate).ToArray();
            //    DeleteInternal<TEntity, TKey>(entities);
            //    count = await DbContext.SaveChangesAsync(CancellationTokenProvider.Token);
            //}
            //else
            //{
            //    // 物理删除
            //    count = await DbSet.Where(predicate).DeleteAsync(CancellationTokenProvider.Token);
            //}

            //await unitOfWork.CommitAsync(CancellationTokenProvider.Token);

            //return OperationResult.Success(count, I18N.T("{0}个记录删除成功", count));
            #endregion

            TEntity[] entities = DbSet.Where(predicate).ToArray();
            return await DeleteAsync(entities);
        }
        #endregion
        #region "异步更新实体对象"
        /// <summary>
        /// 异步更新实体对象
        /// </summary>
        /// <param name="entities">更新后的实体对象</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> UpdateAsync(params TEntity[] entities)
        {
            Check.NotNull(entities, nameof(entities));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            entities = CheckUpdate<TEntity, TKey>(entities);
            ((DbContext)DbContext).Update<TEntity, TKey>(entities);
            object count = await DbContext.SaveChangesAsync(CancellationTokenProvider.Token);

            await unitOfWork.CommitAsync(CancellationTokenProvider.Token);

            return OperationResult.Success(count, I18N.T("{0}个记录更新成功", count));
        }
        #endregion
        #region "异步以DTO为载体批量更新实体"
        /// <summary>
        /// 异步以DTO为载体批量更新实体
        /// </summary>
        /// <typeparam name="TEditDto">更新DTO类型</typeparam>
        /// <param name="dtos">更新DTO信息集合</param>
        /// <param name="checkAction">更新信息合法性检查委托</param>
        /// <param name="updateFunc">由DTO到实体的转换委托</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> UpdateAsync<TEditDto>(ICollection<TEditDto> dtos, Func<TEditDto, TEntity, Task> checkAction = null, Func<TEditDto, TEntity, Task<TEntity>> updateFunc = null)
            where TEditDto : IInputDto<TKey>
        {
            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);

            foreach (TEditDto dto in dtos)
            {
                try
                {
                    TEntity entity = await DbSet.FindAsync(dto.Id);
                    if (entity == null)
                    {
                        return OperationResult.NotFound(I18N.T("编号为 {0} 的 {1} 不存在", dto.Id, typeof(TEntity).GetDescription()));
                    }
                    if (checkAction != null)
                    {
                        await checkAction(dto, entity);
                    }
                    entity = dto.MapTo(entity);
                    entity = CheckUpdate<TEntity, TKey>(entity)[0];

                    if (updateFunc != null)
                    {
                        entity = await updateFunc(dto, entity);
                    }

                    ((DbContext)DbContext).Update<TEntity, TKey>(entity);
                }
                catch (Exception e)
                {
                    Logger.LogError(e, "{msg}", e.Message);
                    return OperationResult.Error(e.Message);
                }
            }
            object count = await DbContext.SaveChangesAsync(CancellationTokenProvider.Token);

            await unitOfWork.CommitAsync(CancellationTokenProvider.Token);

            return OperationResult.Success(count, I18N.T("{0}个记录更新成功", count));
        }
        #endregion
        #region "异步更新所有符合特定条件的实体"
        /// <summary>
        /// 异步更新所有符合特定条件的实体
        /// </summary>
        /// <param name="predicate">查询条件谓语表达式</param>
        /// <param name="updateExpression">实体更新表达式</param>
        /// <returns>业务操作结果</returns>
        public virtual async Task<OperationResult> UpdateBatchAsync(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, TEntity>> updateExpression)
        {
            Check.NotNull(predicate, nameof(predicate));
            Check.NotNull(updateExpression, nameof(updateExpression));

            IUnitOfWork unitOfWork = ServiceProvider.GetUnitOfWork(true);
            //走EF.Plus的时候，是不调用SaveChanges的，需要手动开启事务
            ScopedDictionary dict = ServiceProvider.GetService<ScopedDictionary>();
            await ((DbContextBase)DbContext).BeginOrUseTransactionAsync(dict?.IsolationLevel, CancellationTokenProvider.Token);

            object count = await DbSet.Where(predicate).UpdateAsync(updateExpression, CancellationTokenProvider.Token);

            await unitOfWork.CommitAsync(CancellationTokenProvider.Token);

            return OperationResult.Success(count, I18N.T("{0}个记录更新成功", count));
        }
        #endregion
        #region "异步检查实体是否存在"
        /// <summary>
        /// 异步检查实体是否存在
        /// </summary>
        /// <param name="predicate">查询条件谓语表达式</param>
        /// <param name="id">编辑的实体标识</param>
        /// <returns>是否存在</returns>
        public virtual async Task<bool> CheckExistsAsync(Expression<Func<TEntity, bool>> predicate, TKey id = default)
        {
            predicate.CheckNotNull(nameof(predicate));

            TKey defaultId = default;
            var entity = await DbSet.Where(predicate).Select(m => new { m.Id }).FirstOrDefaultAsync(CancellationTokenProvider.Token);
            bool exists = !typeof(TKey).IsValueType && ReferenceEquals(id, null) || id.Equals(defaultId)
                ? entity != null
                : entity != null && !EntityBase<TKey>.IsKeyEqual(entity.Id, id);
            return exists;
        }
        #endregion
        #region "异步查找指定主键的实体"
        /// <summary>
        /// 异步查找指定主键的实体
        /// </summary>
        /// <param name="key">实体主键</param>
        /// <returns>符合主键的实体，不存在时返回null</returns>
        public virtual async Task<TEntity> GetAsync(TKey key)
        {
            CheckEntityKey(key, nameof(key));

            return await DbSet.FindAsync(key);
        }
        #endregion

        #endregion

        #region "受保护方法"
        #region "检查实体键"
        /// <summary>
        /// 检查实体键
        /// </summary>
        /// <param name="key"></param>
        /// <param name="keyName"></param>
        protected virtual void CheckEntityKey(object key, string keyName)
        {
            key.CheckNotNull(nameof(key));
            keyName.CheckNotNull(nameof(keyName));

            var keyType = key.GetType();
            if (keyType == typeof(int))
            {
                Check.GreaterThan((int)key, keyName, 0);
            }
            else if (keyType == typeof(long))
            {
                Check.GreaterThan((long)key, keyName, 0);
            }
            else if (keyType == typeof(string))
            {
                Check.NotNullOrEmpty((string)key, keyName);
            }
            else if (keyType == typeof(Guid))
            {
                ((Guid)key).CheckNotEmpty(keyName);
            }
        }
        #endregion
        #region "检查指定操作的数据权限，验证要操作的数据是否符合特定的验证委托。"
        /// <summary>
        /// 检查指定操作的数据权限，验证要操作的数据是否符合特定的验证委托。
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <typeparam name="K">实体主键类型</typeparam>
        /// <param name="operation">数据权限操作</param>
        /// <param name="entities">要验证的实体对象</param>
        /// <exception cref="Exception">权限验证异常</exception>
        protected virtual void CheckDataAuth<T, K>(DataAuthOperation operation, params T[] entities)
            where T : IEntity<K>
            where K : IEquatable<K>
        {
            if (entities.Length == 0 || DataAuthService == null) { return; }

            bool flag = DataAuthService.CheckDataAuth(operation, null, entities);
            if (!flag)
            {
                throw new Exception(I18N.T("{0} 数据 {1} 进行 {2} 操作时权限不足", typeof(T).GetDescription(), entities.ExpandAndToString(m => m.Id.ToString()), operation.ToDescription()));
            }
        }
        #endregion

        #region "实体增加前检查并设置相关属性值"
        /// <summary>
        /// 实体增加前检查并设置相关属性值
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <typeparam name="K">实体主键类型</typeparam>
        /// <param name="entities">实体对象</param>
        /// <returns>实体对象</returns>
        protected virtual T[] CheckInsert<T, K>(params T[] entities)
            where T : class, IEntity<K>
            where K : IEquatable<K>
        {
            for (int i = 0; i < entities.Length; i++)
            {
                T entity = entities[i];

                CheckInsertKey<T, K>(entity);

                entities[i] = entity.CheckICreatedTime();
                entities[i] = entity.CheckICreationAudited(Principal);

                entities[i] = entity.CheckIOrganizationAudited(ServiceProvider);
                entities[i] = entity.CheckIDepartmentAudited(ServiceProvider);

                entities[i] = entity.CheckDataVersion<T, K>(ServiceProvider);

                //实体增加删除更新前检查并设置非主键属性
                CheckValueGenerateByInsertDeleteUpdate<T, K>(entity);

                //循环嵌套的子实体对象
                var childEntityProps = entity.GetType().GetProperties().Where(o => o.MemberType == MemberTypes.Property && o.IsVirtual() && o.Name != "Id").ToArray();
                if (childEntityProps?.Length > 0)
                {
                    foreach (var childEntityProp in childEntityProps)
                    {
                        var childValue = childEntityProp.GetValue(entity);
                        if (childValue != null)
                        {
                            if (childValue is IEnumerable childEntities)
                            {
                                foreach (var childEntity in childEntities)
                                {
                                    var childType = childEntity.GetType();
                                    if (childType.IsBaseOn(typeof(IEntity<>)))
                                    {
                                        //MethodInfo mi = GetType().GetMethod("CheckInsert");
                                        MethodInfo mi = GetType().GetRuntimeMethods().First(o => o.Name == "CheckInsert");
                                        MethodInfo miConstructed = mi.MakeGenericMethod(childType, ((dynamic)childEntity).Id.GetType());
                                        ArrayList list = new() { childEntity };
                                        var val = list.ToArray(childType);
                                        miConstructed.Invoke(this, new object[] { val });
                                    }
                                }
                            }
                            else
                            {
                                var childType = childEntityProp.PropertyType;
                                if (childType.IsBaseOn(typeof(IEntity<>)))
                                {
                                    //MethodInfo mi = GetType().GetMethod("CheckInsert");
                                    MethodInfo mi = GetType().GetRuntimeMethods().First(o => o.Name == "CheckInsert");
                                    MethodInfo miConstructed = mi.MakeGenericMethod(childType, ((dynamic)childValue).Id.GetType());
                                    ArrayList list = new() { childValue };
                                    var val = list.ToArray(childType);
                                    miConstructed.Invoke(this, new object[] { val });
                                }
                            }
                        }
                    }
                }
            }
            return entities;
        }
        #endregion
        #region "实体更新前检查并设置相关属性值"
        /// <summary>
        /// 实体更新前检查并设置相关属性值
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <typeparam name="K">实体主键类型</typeparam>
        /// <param name="entities">实体对象</param>
        /// <returns>实体对象</returns>
        protected virtual T[] CheckUpdate<T, K>(params T[] entities)
            where T : IEntity<K>
            where K : IEquatable<K>
        {
            CheckDataAuth<T, K>(DataAuthOperation.Update, entities);

            for (var i = 0; i < entities.Length; i++)
            {
                T entity = entities[i];

                entities[i] = entity.CheckIUpdatedTime();
                entities[i] = entity.CheckIUpdateAudited(Principal);

                entities[i] = entity.CheckDataVersion<T, K>(ServiceProvider);

                //实体增加删除更新前检查并设置非主键属性
                CheckValueGenerateByInsertDeleteUpdate<T, K>(entity);

                ////循环嵌套的子实体对象---导致无限循环，注释备查
                //var childEntityProps = entity.GetType().GetProperties().Where(o => o.MemberType == MemberTypes.Property && o.IsVirtual() && o.Name != "Id").ToArray();
                //if (childEntityProps?.Length > 0)
                //{
                //    foreach (var childEntityProp in childEntityProps)
                //    {
                //        var childValue = childEntityProp.GetValue(entity);
                //        if (childValue != null)
                //        {
                //            if (childValue is IEnumerable childEntities)
                //            {
                //                foreach (var childEntity in childEntities)
                //                {
                //                    var childType = childEntity.GetType();
                //                    if (childType.IsBaseOn(typeof(IEntity<>)))
                //                    {
                //                        //MethodInfo mi = GetType().GetMethod("CheckUpdate");
                //                        MethodInfo mi = GetType().GetRuntimeMethods().First(o => o.Name == "CheckUpdate");
                //                        MethodInfo miConstructed = mi.MakeGenericMethod(childType, ((dynamic)childEntity).Id.GetType());
                //                        ArrayList list = new() { childEntity };
                //                        var val = list.ToArray(childType);
                //                        miConstructed.Invoke(this, new object[] { val });
                //                    }
                //                }
                //            }
                //            else
                //            {
                //                var childType = childEntityProp.PropertyType;
                //                if (childType.IsBaseOn(typeof(IEntity<>)))
                //                {
                //                    //MethodInfo mi = GetType().GetMethod("CheckUpdate");
                //                    MethodInfo mi = GetType().GetRuntimeMethods().First(o => o.Name == "CheckUpdate");
                //                    MethodInfo miConstructed = mi.MakeGenericMethod(childType, ((dynamic)childValue).Id.GetType());
                //                    ArrayList list = new() { childValue };
                //                    var val = list.ToArray(childType);
                //                    miConstructed.Invoke(this, new object[] { val });
                //                }
                //            }
                //        }
                //    }
                //}
            }

            return entities;
        }
        #endregion
        #region "实体删除(内部方法)"
        /// <summary>
        /// 实体删除(内部方法)
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <typeparam name="K">实体主键类型</typeparam>
        /// <param name="entities">实体对象</param>
        protected virtual void DeleteInternal<T, K>(params T[] entities)
            where T : class, IEntity<K>
            where K : IEquatable<K>
        {
            CheckDataAuth<T, K>(DataAuthOperation.Delete, entities);

            for (var i = 0; i < entities.Length; i++)
            {
                T entity = entities[i];

                if (typeof(ISoftDeletable).IsAssignableFrom(typeof(T)))
                {
                    entity.CheckDataVersion<T, K>(ServiceProvider);

                    ISoftDeletable softDeletableEntity = (ISoftDeletable)entity;
                    softDeletableEntity.DeletedTime = DateTime.Now;

                    //实体增加删除更新前检查并设置非主键属性
                    CheckValueGenerateByInsertDeleteUpdate<T, K>(entity);

                    // 逻辑删除
                    //DbSet.UpdateRange(entity);
                    var dbSet = ((DbContext)DbContext).Set<T>();
                    dbSet.UpdateRange(entity);
                }
                else
                {
                    // 物理删除
                    //DbSet.RemoveRange(entity);
                    var dbSet = ((DbContext)DbContext).Set<T>();
                    dbSet.RemoveRange(entity);
                }

                ////循环嵌套的子实体对象---导致无限循环，注释备查
                //var childEntityProps = entity.GetType().GetProperties().Where(o => o.MemberType == MemberTypes.Property && o.IsVirtual() && o.Name != "Id").ToArray();
                //if (childEntityProps?.Length > 0)
                //{
                //    foreach (var childEntityProp in childEntityProps)
                //    {
                //        var childValue = childEntityProp.GetValue(entity);
                //        if (childValue != null)
                //        {
                //            if (childValue is IEnumerable childEntities)
                //            {
                //                foreach (var childEntity in childEntities)
                //                {
                //                    var childType = childEntity.GetType();
                //                    if (childType.IsBaseOn(typeof(IEntity<>)))
                //                    {
                //                        //MethodInfo mi = GetType().GetMethod("DeleteInternal");
                //                        MethodInfo mi = GetType().GetRuntimeMethods().First(o => o.Name == "DeleteInternal");
                //                        MethodInfo miConstructed = mi.MakeGenericMethod(childType, ((dynamic)childEntity).Id.GetType());
                //                        ArrayList list = new() { childEntity };
                //                        var val = list.ToArray(childType);
                //                        miConstructed.Invoke(this, new object[] { val });
                //                    }
                //                }
                //            }
                //            else
                //            {
                //                var childType = childEntityProp.PropertyType;
                //                if (childType.IsBaseOn(typeof(IEntity<>)))
                //                {
                //                    //MethodInfo mi = GetType().GetMethod("DeleteInternal");
                //                    MethodInfo mi = GetType().GetRuntimeMethods().First(o => o.Name == "DeleteInternal");
                //                    MethodInfo miConstructed = mi.MakeGenericMethod(childType, ((dynamic)childValue).Id.GetType());
                //                    ArrayList list = new() { childValue };
                //                    var val = list.ToArray(childType);
                //                    miConstructed.Invoke(this, new object[] { val });
                //                }
                //            }
                //        }
                //    }
                //}
            }
        }
        #endregion

        #region "实体增加前检查并设置实体键"
        /// <summary>
        /// 实体增加前检查并设置实体键
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="K"></typeparam>
        /// <param name="entity"></param>
        protected virtual void CheckInsertKey<T, K>(T entity)
            where T : class, IEntity<K>
            where K : IEquatable<K>
        {
            var keyType = typeof(K);
            if (keyType == typeof(Guid))
            {
                SetGuidKey<T, K>(entity);
            }
            else if (keyType == typeof(int))
            {
                SetInt32Key<T, K>(entity);
            }
            else if (keyType == typeof(long))
            {
                SetInt64Key<T, K>(entity);
            }
            else if (keyType == typeof(string))
            {
                entity.Id = entity.Id.CastTo("").Trim().CastTo<K>();
                Check.NotNullOrEmpty(entity.Id.CastTo(""), nameof(entity.Id));
            }
            else
            {
                Check.NotNull(entity.Id, nameof(entity.Id));
            }
        }
        #endregion
        #region "设置类型为Guid的实体主键"
        /// <summary>
        /// 设置类型为Guid的实体主键
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <typeparam name="K">实体主键类型</typeparam>
        /// <param name="entity">实体对象</param>
        protected virtual void SetGuidKey<T, K>(T entity)
            where T : IEntity<K>
            where K : IEquatable<K>
        {
            if (entity.Id.GetType().Equals(typeof(Guid)))
            {
                DatabaseType databaseType = DbContext.GetDatabaseType();
                ISequentialGuidGenerator generator = ServiceProvider.GetServices<ISequentialGuidGenerator>().FirstOrDefault(m => m.DatabaseType == databaseType);

                var valueGenerateAttribute = entity.GetType().GetAttribute<ValueGenerateAttribute>();
                if (valueGenerateAttribute == null)
                {
                    if (entity.Id.Equals(default(Guid)))
                    {
                        //设置新值
                        entity.Id = generator == null ? SequentialGuid.Create(databaseType).CastTo<K>() : generator.Create().CastTo<K>();
                    }
                }
                else if (valueGenerateAttribute.GenerateMode != ValueGenerateMode.Manual)
                {
                    if (valueGenerateAttribute.Forced || entity.Id.Equals(default(Guid)))
                    {
                        //设置新值
                        entity.Id = generator == null ? SequentialGuid.Create(databaseType).CastTo<K>() : generator.Create().CastTo<K>();
                    }
                }
            }
        }
        #endregion
        #region "设置类型为Int32的实体主键"
        /// <summary>
        /// 设置类型为Int32的实体主键
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <typeparam name="K">实体主键类型</typeparam>
        /// <param name="entity">实体对象</param>
        /// <exception cref="Exception">操作异常</exception>
        protected virtual void SetInt32Key<T, K>(T entity)
            where T : class, IEntity<K>
            where K : IEquatable<K>
        {
            if (entity.Id.GetType().Equals(typeof(int)))
            {
                var valueGenerateAttribute = entity.GetType().GetAttribute<ValueGenerateAttribute>();
                if (valueGenerateAttribute != null)
                {
                    if (valueGenerateAttribute.Forced || entity.Id.Equals(default(int)))
                    {
                        //设置新值
                        switch (valueGenerateAttribute.GenerateRule)
                        {
                            case ValueGenerateRule.Never:
                                switch (valueGenerateAttribute.GenerateMode)
                                {
                                    case ValueGenerateMode.Manual:
                                        break;
                                    case ValueGenerateMode.AutoIncrease:
                                        //设置新值：自动增加算法
                                        var dbSet = ((DbContext)DbContext).Set<T>();
                                        var maxKeyItem = dbSet.AsQueryable().OrderByDescending(o => o.Id).Select(m => new { m.Id }).FirstOrDefault();
                                        var maxKey = maxKeyItem != null ? maxKeyItem.Id : 0.CastTo<K>();
                                        entity.Id = (maxKey.CastTo(0) + 1).CastTo<K>();
                                        break;
                                    case ValueGenerateMode.DateTimeIncrease:
                                        throw new Exception(I18N.T("表 {0} 主键类型 Int32 由于最大值限制，不支持按日期时间增长方式。", DbContext.GetTableName(typeof(T))));
                                    case ValueGenerateMode.Snowflake:
                                        //设置新值(采用雪花算法简易算法)
                                        var snowflakeKeyGenerator = ServiceProvider.GetRequiredService<ISnowflakeKeyGenerator<int>>();
                                        entity.Id = snowflakeKeyGenerator.Create().CastTo<K>();
                                        break;
                                }
                                break;
                            default:
                                entity.Id = 0.CastTo<K>();
                                break;
                        }
                    }
                }

                #region "无效代码，注释暂留"
                ////利用追踪图获取到对象所有状态和主键是否已经设置
                //_dbContext.GetChangeTracker().TrackGraph(entity, node =>
                //{
                //    if (node.Entry.IsKeySet)
                //    {
                //        //当主键已经设置时，设置新值为0，始终使用数据库自增长值
                //        entity.Id = 0.CastTo<TKey>();
                //    }
                //    else
                //    {
                //        var snowflakeKeyGenerator = _serviceProvider.GetService<ISnowflakeKeyGenerator<int>>();

                //        var valueGenerateAttribute = entity.GetType().GetAttribute<ValueGenerateAttribute>();
                //        if (valueGenerateAttribute == null)
                //        {
                //            //设置新值(采用雪花算法简易算法)
                //            entity.Id = snowflakeKeyGenerator.Create().CastTo<TKey>();
                //            //entity.Id = SnowflakeIdGeneratorSimple.NewId().CastTo<TKey>();
                //        }
                //        else
                //        {
                //            switch (valueGenerateAttribute.GenerateMode)
                //            {
                //                case ValueGenerateMode.Manual:
                //                    break;
                //                case ValueGenerateMode.AutoIncrease:
                //                    //TODO：自动增加算法
                //                    break;
                //                case ValueGenerateMode.Snowflake:
                //                    //设置新值(采用雪花算法简易算法)
                //                    entity.Id = snowflakeKeyGenerator.Create().CastTo<TKey>();
                //                    break;
                //            }
                //        }

                //    }
                //});
                #endregion
            }
        }
        #endregion
        #region "设置类型为Int64的实体主键"
        /// <summary>
        /// 设置类型为Int64的实体主键
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <typeparam name="K">实体主键类型</typeparam>
        /// <param name="entity">实体对象</param>
        protected virtual void SetInt64Key<T, K>(T entity)
            where T : class, IEntity<K>
            where K : IEquatable<K>
        {
            if (entity.Id.GetType().Equals(typeof(long)))
            {
                var valueGenerateAttribute = entity.GetType().GetAttribute<ValueGenerateAttribute>();
                if (valueGenerateAttribute != null)
                {
                    if (valueGenerateAttribute.Forced || entity.Id.Equals(default(long)))
                    {
                        //设置新值
                        switch (valueGenerateAttribute.GenerateRule)
                        {
                            case ValueGenerateRule.Never:
                                switch (valueGenerateAttribute.GenerateMode)
                                {
                                    case ValueGenerateMode.Manual:
                                        break;
                                    case ValueGenerateMode.AutoIncrease:
                                        //设置新值：自动增加算法
                                        var dbSet = ((DbContext)DbContext).Set<T>();
                                        var maxKeyItem = dbSet.AsQueryable().OrderByDescending(o => o.Id).Select(m => new { m.Id }).FirstOrDefault();
                                        var maxKey = maxKeyItem != null ? maxKeyItem.Id : 0.CastTo<K>();
                                        entity.Id = (maxKey.CastTo<long>(0) + 1).CastTo<K>();
                                        break;
                                    case ValueGenerateMode.DateTimeIncrease:
                                        var dateTimeIncreaseVal = DateTime.UtcNow.ToString("yyyyMMddHHmmssfffff").CastTo<long>();
                                        entity.Id = dateTimeIncreaseVal.CastTo<K>();
                                        break;
                                    case ValueGenerateMode.Snowflake:
                                        //设置新值(采用雪花算法)
                                        var snowflakeKeyGenerator = ServiceProvider.GetRequiredService<ISnowflakeKeyGenerator<long>>();
                                        entity.Id = snowflakeKeyGenerator.Create().CastTo<K>();
                                        break;
                                }
                                break;
                            default:
                                entity.Id = 0.CastTo<K>();
                                break;
                        }
                    }
                }
            }
        }
        #endregion

        #region "实体增加删除更新前检查并设置非主键属性"
        /// <summary>
        /// 实体增加删除更新前检查并设置非主键属性
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <typeparam name="K">实体主键类型</typeparam>
        /// <param name="entity">实体对象</param>
        /// <returns>实体对象</returns>
        /// <exception cref="Exception">操作异常</exception>
        protected virtual T CheckValueGenerateByInsertDeleteUpdate<T, K>(T entity)
            where T : IEntity<K>
            where K : IEquatable<K>
        {
            //设置自增字段
            var valueGenerateProps = entity.GetType().GetProperties().Where(o => o.MemberType == MemberTypes.Property && !o.IsVirtual() && o.GetAttribute<ValueGenerateAttribute>() != null && (o.GetAttribute<KeyAttribute>() == null && !o.Name.ToUpper().Equals("ID"))).ToArray();
            if (valueGenerateProps != null)
            {
                foreach (var valueGenerateProp in valueGenerateProps)
                {
                    var valueGenerateAttribute = valueGenerateProp.PropertyType.GetAttribute<ValueGenerateAttribute>();
                    if (valueGenerateAttribute != null)
                    {
                        if (typeof(Guid).Equals(valueGenerateProp.PropertyType))
                        {
                            if (valueGenerateAttribute.Forced || entity.Id.Equals(default(Guid)))
                            {
                                if (valueGenerateAttribute.GenerateMode != ValueGenerateMode.Manual)
                                {
                                    DatabaseType databaseType = DbContext.GetDatabaseType();
                                    ISequentialGuidGenerator generator = ServiceProvider.GetServices<ISequentialGuidGenerator>().FirstOrDefault(m => m.DatabaseType == databaseType);
                                    //设置新值
                                    valueGenerateProp.SetValue(entity, generator == null ? SequentialGuid.Create(databaseType) : generator.Create());
                                }
                            }
                        }
                        else if (typeof(int).Equals(valueGenerateProp.PropertyType))
                        {
                            if (valueGenerateAttribute.Forced || entity.Id.Equals(default(int)))
                            {
                                //设置新值
                                switch (valueGenerateAttribute.GenerateRule)
                                {
                                    case ValueGenerateRule.Never:
                                        switch (valueGenerateAttribute.GenerateMode)
                                        {
                                            case ValueGenerateMode.Manual:
                                                break;
                                            case ValueGenerateMode.AutoIncrease:
                                                //设置新值：自动增加算法
                                                valueGenerateProp.SetValue(entity, valueGenerateProp.GetValue(entity).CastTo<int>(0) + 1);
                                                break;
                                            case ValueGenerateMode.DateTimeIncrease:
                                                //Int32类型不支持
                                                throw new Exception(I18N.T("表 {0} 主键类型 Int32 由于最大值限制，不支持按日期时间增长方式。", DbContext.GetTableName(typeof(TEntity))));
                                            case ValueGenerateMode.Snowflake:
                                                //设置新值(采用雪花算法简易算法)
                                                var snowflakeKeyGenerator = ServiceProvider.GetService<ISnowflakeKeyGenerator<int>>();
                                                valueGenerateProp.SetValue(entity, snowflakeKeyGenerator.Create());
                                                break;
                                        }
                                        break;
                                    default:
                                        valueGenerateProp.SetValue(entity, 0);
                                        break;
                                }
                            }
                        }
                        else if (typeof(long).Equals(valueGenerateProp.PropertyType))
                        {
                            if (valueGenerateAttribute.Forced || entity.Id.Equals(default(long)))
                            {
                                switch (valueGenerateAttribute.GenerateRule)
                                {
                                    case ValueGenerateRule.Never:
                                        switch (valueGenerateAttribute.GenerateMode)
                                        {
                                            case ValueGenerateMode.Manual:
                                                break;
                                            case ValueGenerateMode.AutoIncrease:
                                                //设置新值：自动增加算法
                                                valueGenerateProp.SetValue(entity, valueGenerateProp.GetValue(entity).CastTo<long>(0) + 1);
                                                break;
                                            case ValueGenerateMode.DateTimeIncrease:
                                                var dateTimeIncreaseVal = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff").CastTo<long>(0);
                                                valueGenerateProp.SetValue(entity, dateTimeIncreaseVal);
                                                break;
                                            case ValueGenerateMode.Snowflake:
                                                //设置新值(采用雪花算法)
                                                var snowflakeKeyGenerator = ServiceProvider.GetService<ISnowflakeKeyGenerator<long>>();
                                                valueGenerateProp.SetValue(entity, snowflakeKeyGenerator.Create());
                                                break;
                                        }
                                        break;
                                    default:
                                        valueGenerateProp.SetValue(entity, 0);
                                        break;
                                }
                            }
                        }
                        else if (typeof(string).Equals(valueGenerateProp.PropertyType))
                        {
                            if (valueGenerateAttribute.Forced || entity.Id.Equals(default(string)))
                            {
                                //设置新值
                            }
                        }
                        else
                        {

                        }
                    }
                }
            }
            return entity;
        }
        #endregion

        #endregion

    }

}
